#include "Demo.h"
#include <windowsx.h>

//////////////////////////////////////////////////////////////////////////
// CDemoApp
//////////////////////////////////////////////////////////////////////////
CDemoApp::CDemoApp()
{

}

CDemoApp::~CDemoApp()
{

}

bool CDemoApp::InitInstance()
{
	m_pMainWnd = new CDemoWnd();
	m_pMainWnd->ShowWindow(SW_SHOW);
																   
	return true;
}

//////////////////////////////////////////////////////////////////////////
// CDemoWnd
//////////////////////////////////////////////////////////////////////////
#define MSGHANDLE(nMsg, MsgProc)  {(nMsg), (&CDemoWnd::MsgProc)}

const CDemoWnd::TMSGMAP CDemoWnd::MsgMapTable[] = {
	MSGHANDLE(WM_CREATE,	OnCreate),
	MSGHANDLE(WM_DESTROY,	OnDestroy), 
	MSGHANDLE(WM_PAINT,		OnPaint),
};

CDemoWnd::CDemoWnd()
{
	Create(_T("Demo Pen"), WS_OVERLAPPEDWINDOW, 0, 0, 800, 480, NULL);
}

CDemoWnd::~CDemoWnd()
{

}

LRESULT	 CDemoWnd::WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	for (int ii = 0; ii < sizeof(MsgMapTable) / sizeof(*MsgMapTable); ii++)
	{
		if (nMsg == MsgMapTable[ii].m_nMsg)
		{
			(this->*MsgMapTable[ii].m_MsgProc)(hWnd, nMsg, wParam, lParam);
			break;
		}
	}

	return __super::FinalWndProc(hWnd, nMsg, wParam, lParam);
}

LRESULT CDemoWnd::OnCreate(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	CenterWindow();

	return 0;
}

LRESULT CDemoWnd::OnDestroy(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	PostQuitMessage(0);

	return 0;
}

LRESULT CDemoWnd::OnPaint(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hDC = BeginPaint(hWnd, &ps);
	
	RECT rtGrids[3][2];

	DemoPen(hDC, rtGrids);

	DemoCreatePen(hDC, rtGrids[0][1]);

	DemoCreatePenIndirect(hDC, rtGrids[1][1]);

	DemoExtCreatePen(hDC, rtGrids[2][1]);

	EndPaint(hWnd, &ps);

	return 1;
}

void CDemoWnd::DemoPen(HDC hDC, RECT (&rtGrids)[3][2])
{
	SelectObject(hDC, GetStockObject(DC_PEN));
	SetDCPenColor(hDC, RGB(0, 0, 255));

	RECT rtClient;
	GetClientRect(m_hWnd, &rtClient);
	InflateRect(&rtClient, 10, 10);
	int nLeftGridW = (rtClient.right - rtClient.left) / 3;
	int nLeftGridH = (rtClient.bottom - rtClient.top) / 3;
	
	for (int ii = 0; ii < 3; ii++)
	{
		rtGrids[ii][0].left		= rtClient.left;  
		rtGrids[ii][0].right	= rtGrids[ii][0].left + nLeftGridW;
		rtGrids[ii][0].top		= rtClient.top + ii * nLeftGridH;
		rtGrids[ii][0].bottom	= rtGrids[ii][0].top + nLeftGridH;
	}

	for (int ii = 0; ii < 3; ii++)
	{
		rtGrids[ii][1].left		= rtClient.left + nLeftGridW; 
		rtGrids[ii][1].right	= rtClient.right;
		rtGrids[ii][1].top		= rtClient.top + ii * nLeftGridH;
		rtGrids[ii][1].bottom	= rtGrids[ii][1].top + nLeftGridH;
	}

	MoveToEx(hDC, rtClient.left + nLeftGridW, rtClient.top, NULL);
	LineTo(hDC, rtClient.left + nLeftGridW, rtClient.bottom);

	for (int ii = 0; ii < 3; ii++)
	{
		MoveToEx(hDC, rtClient.left, rtClient.top + (ii + 1) * nLeftGridH, NULL);
		LineTo(hDC, rtClient.right, rtClient.top + (ii + 1) * nLeftGridH);
	}

	const TCHAR* szDesInfo[] = {
		_T("<CreatePen> Draw line"), 
		_T("<CreatePenIndirect> Draw line"),
		_T("<ExtCreatePen> Draw line") };
	for (int ii = 0; ii < 3; ii++)
	{
		DrawText(hDC, szDesInfo[ii], -1, &rtGrids[ii][0], DT_SINGLELINE|DT_VCENTER|DT_CENTER);
	}

	return;
}

void CDemoWnd::DemoCreatePen(HDC hDC, const RECT& rtGrid)
{
	int nLineType[] = {
		PS_SOLID,
		PS_DASH,
		PS_DOT,
		PS_DASHDOT,
		PS_DASHDOTDOT,
		PS_NULL,
		PS_INSIDEFRAME
	};
	
	int nCount	= sizeof(nLineType) / sizeof(*nLineType);
	int nHeight = (rtGrid.bottom - rtGrid.top) / (nCount + 1);

	for (int ii = 0; ii < nCount; ii++)
	{
		HPEN hPen = CreatePen(nLineType[ii], 1, RGB(255, 0, 0));
		HPEN hOld = static_cast<HPEN>(SelectObject(hDC, hPen));

		MoveToEx(hDC, rtGrid.left + 10, (ii + 1) * nHeight, NULL);
		LineTo(hDC, rtGrid.right - 20, (ii + 1) * nHeight);

		SelectObject(hDC, hOld);
		DeleteObject(hPen);
	}

	return;
}

void CDemoWnd::DemoCreatePenIndirect(HDC hDC, const RECT& rtGrid)
{
	int nLineType[] = {
		PS_SOLID,
		PS_DASH,
		PS_DOT,
		PS_DASHDOT,
		PS_DASHDOTDOT,
		PS_NULL,
		PS_INSIDEFRAME
	};

	int nCount	= sizeof(nLineType) / sizeof(*nLineType);
	int nHeight = (rtGrid.bottom - rtGrid.top) / (nCount + 1);

	for (int ii = 0; ii < nCount; ii++)
	{
		POINT ptPoint = {1, 2};

		LOGPEN LogPen;
		LogPen.lopnColor	= RGB(255, 0, 0);
		LogPen.lopnStyle	= nLineType[ii];
		LogPen.lopnWidth	= ptPoint;
		HPEN hPen = CreatePenIndirect(&LogPen);
		HPEN hOld = static_cast<HPEN>(SelectObject(hDC, hPen));

		MoveToEx(hDC, rtGrid.left + 10, rtGrid.top + (ii + 1) * nHeight, NULL);
		LineTo(hDC, rtGrid.right - 20, rtGrid.top + (ii + 1) * nHeight);

		SelectObject(hDC, hOld);
		DeleteObject(hPen);
	}

	return;
}

void CDemoWnd::DemoExtCreatePen(HDC hDC, const RECT& rtGrid)
{
	int nLineType[] = {
		PS_SOLID,
		PS_DASH,
		PS_DOT,
		PS_DASHDOT,
		PS_DASHDOTDOT,
		PS_NULL,
		PS_INSIDEFRAME
	};

	int nCount	= sizeof(nLineType) / sizeof(*nLineType);
	int nHeight = (rtGrid.bottom - rtGrid.top) / (nCount + 1);

	for (int ii = 0; ii < nCount; ii++)
	{
		LOGBRUSH LogBrush;
		LogBrush.lbHatch	= HS_CROSS;
		LogBrush.lbStyle	= BS_SOLID;
		LogBrush.lbColor 	= RGB(255, 0, 0);
		
		HPEN hPen = ExtCreatePen(PS_GEOMETRIC|PS_ENDCAP_SQUARE|PS_JOIN_ROUND|nLineType[ii], 6, &LogBrush, 0, NULL);
		//HPEN hPen = ExtCreatePen(PS_COSMETIC|PS_ENDCAP_SQUARE|nLineType[ii], 1, &LogBrush, 0, NULL);

		HPEN hOld = static_cast<HPEN>(SelectObject(hDC, hPen));

		MoveToEx(hDC, rtGrid.left + 10, rtGrid.top + (ii + 1) * nHeight, NULL);
		LineTo(hDC, rtGrid.right - 20, rtGrid.top + (ii + 1) * nHeight);

		SelectObject(hDC, hOld);
		DeleteObject(hPen);
	}

	return;
}